use actix_web::{HttpResponse, ResponseError};
use actix_web::http::StatusCode;
use derive_more::Display;
use rand::{
    distributions::{Distribution, Standard},
    Rng, thread_rng,
};
use serde::export::fmt::Error;
//use std::fmt::Display;
use serde::export::Formatter;
use serde_derive::{Deserialize, Serialize};

// Display推断有点问题。。
#[derive(Debug/*, Display*/)]
pub enum ConcreteError {
    //#[display(fmt = "Concrete Error 1")]
    ConcreteOne,
    //#[display(fmt = "Concrete Error 2")]
    ConcreteTwo,
    //#[display(fmt = "Concrete Error 3")]
    ConcreteThree,
    //#[display(fmt = "Concrete Error 4")]
    ConcreteFour,
}

impl std::fmt::Display for ConcreteError {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        match self {
            ConcreteError::ConcreteOne => {
                write!(f, "occur {}", "concrete one")
            }
            ConcreteError::ConcreteTwo => {
                write!(f, "occur {}", "concrete two")
            }
            ConcreteError::ConcreteThree => {
                write!(f, "occur {}", "concrete three")
            }
            ConcreteError::ConcreteFour => {
                write!(f, "occur {}", "concrete four")
            }
        }
    }
}

impl Distribution<ConcreteError> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ConcreteError {
        match rng.gen_range(1, 5) {
            1 => ConcreteError::ConcreteOne,
            2 => ConcreteError::ConcreteTwo,
            3 => ConcreteError::ConcreteThree,
            _ => ConcreteError::ConcreteFour,
        }
    }
}

impl ResponseError for ConcreteError {
    fn error_response(&self) -> HttpResponse {
        match self {
            ConcreteError::ConcreteOne => {
                println!("one");
                HttpResponse::Forbidden().body(format!("{}", ConcreteError::ConcreteOne))
            }
            ConcreteError::ConcreteTwo => {
                println!("two");
                HttpResponse::Unauthorized().body(format!("{}", ConcreteError::ConcreteTwo))
            }
            ConcreteError::ConcreteThree => {
                println!("three");
                HttpResponse::InternalServerError().body(format!("{}", ConcreteError::ConcreteThree))
            }
            ConcreteError::ConcreteFour => {
                println!("four");
                HttpResponse::BadRequest().body(format!("{}", ConcreteError::ConcreteFour))
            }
        }
    }
}

pub async fn do_something_random() -> Result<(), ConcreteError> {
    let mut rng = thread_rng();

    if rng.gen_bool(2.0 / 10.0) {
        Ok(())
    } else {
        Err(rand::random::<ConcreteError>())
    }
}